package com.coe3.datahandler;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import com.coe3.data.Information;

import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ImageView.ScaleType;

public class DrawableManager {
    private final Map<String, Drawable> drawableMap;
    private static DrawableManager instance;

    public DrawableManager() {
        drawableMap = new HashMap<String, Drawable>();
    }
 
    public static DrawableManager getInstance() {
        if( instance == null ) {
            instance = new DrawableManager();
        }
        return instance;
    }
    
    public Drawable drawableMapWith( final String urlString ) {
        if ( drawableMap.containsKey( urlString ) ) {
            return drawableMap.get( urlString );
        }

        return null;
    }

    public Drawable fetchDrawable(String urlString) {
        if ( drawableMap.containsKey( urlString ) ) {
            return drawableMap.get( urlString );
        }

        try {
            InputStream is = fetch(urlString);
            Drawable drawable = Drawable.createFromStream( new FlushedInputStream( is ), "src" );
            if (drawable != null) {
	            drawableMap.put(urlString, drawable);
	            Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
	                    + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
	                    + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth()
	                    + ((BitmapDrawable)drawable).getBitmap().getWidth() + "," + ((BitmapDrawable)drawable).getBitmap().getHeight());
            } else {
            	Log.w( this.getClass().getSimpleName(), "could not get thumbnail" );
            }
            return drawable;
        } catch (MalformedURLException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        } catch (IOException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        } catch ( NullPointerException e ) {
        	Log.e(this.getClass().getSimpleName(), "null pointer exception", e);
        	return null;
        } catch ( Exception e ) {
        	Log.e(this.getClass().getSimpleName(), "other pointer exception", e);
        	return null;
        }
    }
    
    public void fetchDrawableOnThread( final String urlString, final ImageView imageView ) {
    	this.fetchDrawableOnThread(urlString, imageView, -1);
    }

    public void fetchDrawableOnThread( final String urlString, final ImageView imageView, int defaultId ) {
		if( defaultId != -1 )
			imageView.setImageResource( defaultId );
		
		if( urlString == null ) {
    		Log.d(this.getClass().getSimpleName(), "Error!! Fetch drawable with null string url.");
		} else if( urlString.trim().equalsIgnoreCase("") ) {
    		Log.d(this.getClass().getSimpleName(), "Error!! Fetch drawable with null string url.");
    	} else if( drawableMap.containsKey( urlString ) ) {
    		if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageView") )
    			imageView.setImageDrawable( drawableMap.get( urlString ) );
    	} else {
    		final Handler handler = new Handler() {
    			@Override
    			public void handleMessage(Message message) {
    				Log.d( "Fetch Handler", "URL: " + urlString + " Tag: " + imageView.getTag() );
    				if( imageView.getTag() == null ) {
    					if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageView") )
    						imageView.setImageDrawable((Drawable) message.obj);
    					else if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageButton") )
    						imageView.setBackgroundDrawable( (Drawable) message.obj );
    				} else if( imageView.getTag().toString().equalsIgnoreCase( urlString ) ) {
    					if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageView") )
    						imageView.setImageDrawable((Drawable) message.obj);
    					else if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageButton") )
    						imageView.setBackgroundDrawable( (Drawable) message.obj );
    				}
    				FetchQueue.getInstance().didComplete( this );
    			}
    		};

			Log.d( this.getClass().getSimpleName(), "Fetch URL: " + urlString );
    		FetchQueue.getInstance().setDrawableManager(this);
    		FetchQueue.getInstance().push( handler, urlString );
    	}
    }
    
    public void fetchDrawableOnThread( final View.OnClickListener eventAction, final String urlString, final ImageView imageView, int defaultId ) {
		if( defaultId != -1 )
			imageView.setImageResource( defaultId );
		
		if( urlString == null ) 
		{
    		Log.d(this.getClass().getSimpleName(), "Error!! Fetch drawable with null string url.");
		} 
		else if( urlString.trim().equalsIgnoreCase("") ) 
		{
    		Log.d(this.getClass().getSimpleName(), "Error!! Fetch drawable with null string url.");
    	}
		else if( drawableMap.containsKey( urlString ) ) 
		{
    		if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageView") )
    		{
    			imageView.setImageDrawable( drawableMap.get( urlString ) );
    			Log.d(Information.TAG_DBUG, "urlString: " + urlString);
    			
    			//Add Event Action
    			imageView.setOnClickListener(eventAction);
    		}
    	}
		else 
		{
    		final Handler handler = new Handler()
    		{
    			@SuppressWarnings("deprecation")
				@Override
    			public void handleMessage(Message message) {
    				Log.d( "Fetch Handler", "URL: " + urlString + " Tag: " + imageView.getTag() );
    				if( imageView.getTag() == null ) 
    				{
    					if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageView") )
    					{
    						imageView.setImageDrawable((Drawable) message.obj);
    						Log.d(Information.TAG_DBUG, "imageView.getTag() == null: " + imageView.getClass().getSimpleName());
    		    			
    		    			//Add Event Action
    		    			imageView.setOnClickListener(eventAction);
						}
    					else if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageButton") )
    					{
    						imageView.setBackgroundDrawable( (Drawable) message.obj );
    						Log.d(Information.TAG_DBUG, "imageView.getTag() == null: " + imageView.getClass().getSimpleName());
    		    			
    		    			//Add Event Action
    		    			imageView.setOnClickListener(eventAction);
    					}
    				} 
    				else if( imageView.getTag().toString().equalsIgnoreCase( urlString ) ) 
    				{
    					if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageView") )
    					{
    						imageView.setImageDrawable((Drawable) message.obj);
    						Log.d(Information.TAG_DBUG, "imageView.getTag().toString().equalsIgnoreCase( urlString ): " + imageView.getClass().getSimpleName());
    		    			
    		    			//Add Event Action
    		    			imageView.setOnClickListener(eventAction);
    					}
    					else if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageButton") )
    					{
    						imageView.setBackgroundDrawable( (Drawable) message.obj );
    						Log.d(Information.TAG_DBUG, "imageView.getTag().toString().equalsIgnoreCase( urlString ): " + imageView.getClass().getSimpleName());
    		    			
    		    			//Add Event Action
    		    			imageView.setOnClickListener(eventAction);
    					}
    				}
    				FetchQueue.getInstance().didComplete( this );
    			}
    		};

			Log.d( this.getClass().getSimpleName(), "Fetch URL: " + urlString );
    		FetchQueue.getInstance().setDrawableManager(this);
    		FetchQueue.getInstance().push( handler, urlString );
    	}
    }
    
    public void fetchDrawableOnThread( final View.OnClickListener eventAction, final String urlString, final ImageView imageView, int defaultId, final ViewGroup.LayoutParams params, final ImageView.ScaleType scaleType ) {
		if( defaultId != -1 )
			imageView.setImageResource( defaultId );
		
		if( urlString == null ) 
		{
    		Log.d(this.getClass().getSimpleName(), "Error!! Fetch drawable with null string url.");
		} 
		else if( urlString.trim().equalsIgnoreCase("") ) 
		{
    		Log.d(this.getClass().getSimpleName(), "Error!! Fetch drawable with null string url.");
    	}
		else if( drawableMap.containsKey( urlString ) ) 
		{
    		if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageView") )
    		{
    			imageView.setImageDrawable( drawableMap.get( urlString ) );
    			Log.d(Information.TAG_DBUG, "urlString: " + urlString);
    			
    			//Add Event Action
    			imageView.setOnClickListener(eventAction);
    			imageView.setLayoutParams(params);
    			imageView.setScaleType(scaleType);
    		}
    	}
		else 
		{
    		final Handler handler = new Handler()
    		{
    			@SuppressWarnings("deprecation")
				@Override
    			public void handleMessage(Message message) {
    				Log.d( "Fetch Handler", "URL: " + urlString + " Tag: " + imageView.getTag() );
    				if( imageView.getTag() == null ) 
    				{
    					if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageView") )
    					{
    						imageView.setImageDrawable((Drawable) message.obj);
    						Log.d(Information.TAG_DBUG, "imageView.getTag() == null: " + imageView.getClass().getSimpleName());
    		    			
    		    			//Add Event Action
    		    			imageView.setOnClickListener(eventAction);
    		    			imageView.setLayoutParams(params);
    		    			imageView.setScaleType(scaleType);
						}
    					else if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageButton") )
    					{
    						imageView.setBackgroundDrawable( (Drawable) message.obj );
    						Log.d(Information.TAG_DBUG, "imageView.getTag() == null: " + imageView.getClass().getSimpleName());
    		    			
    		    			//Add Event Action
    		    			imageView.setOnClickListener(eventAction);
    		    			imageView.setLayoutParams(params);
    		    			imageView.setScaleType(scaleType);
    					}
    				} 
    				else if( imageView.getTag().toString().equalsIgnoreCase( urlString ) ) 
    				{
    					if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageView") )
    					{
    						imageView.setImageDrawable((Drawable) message.obj);
    						Log.d(Information.TAG_DBUG, "imageView.getTag().toString().equalsIgnoreCase( urlString ): " + imageView.getClass().getSimpleName());
    		    			
    		    			//Add Event Action
    		    			imageView.setOnClickListener(eventAction);
    		    			imageView.setLayoutParams(params);
    		    			imageView.setScaleType(scaleType);
    					}
    					else if( imageView.getClass().getSimpleName().equalsIgnoreCase("ImageButton") )
    					{
    						imageView.setBackgroundDrawable( (Drawable) message.obj );
    						Log.d(Information.TAG_DBUG, "imageView.getTag().toString().equalsIgnoreCase( urlString ): " + imageView.getClass().getSimpleName());
    		    			
    		    			//Add Event Action
    		    			imageView.setOnClickListener(eventAction);
    		    			imageView.setLayoutParams(params);
    		    			imageView.setScaleType(scaleType);
    					}
    				}
    				FetchQueue.getInstance().didComplete( this );
    			}
    		};

			Log.d( this.getClass().getSimpleName(), "Fetch URL: " + urlString );
    		FetchQueue.getInstance().setDrawableManager(this);
    		FetchQueue.getInstance().push( handler, urlString );
    	}
    }

    private InputStream fetch(String urlString) throws MalformedURLException, IOException {
    	try {
	        DefaultHttpClient httpClient = new DefaultHttpClient();
	        HttpGet request = new HttpGet( urlString );
	        HttpResponse response = httpClient.execute(request);
	        return response.getEntity().getContent();
    	} catch( Exception e ) {
    		e.printStackTrace();
    	}
    	return null;
    }
    
    static class FlushedInputStream extends FilterInputStream {
        public FlushedInputStream(InputStream inputStream) {
            super(inputStream);
        }

        @Override
        public long skip(long n) throws IOException {
            long totalBytesSkipped = 0L;
            while (totalBytesSkipped < n) {
                long bytesSkipped = in.skip(n - totalBytesSkipped);
                if (bytesSkipped == 0L) {
                    int b = read();
                    if (b < 0) {
                        break;  // we reached EOF
                    } else {
                        bytesSkipped = 1; // we read one byte
                    }
                }
                totalBytesSkipped += bytesSkipped;
            }
            return totalBytesSkipped;
        }
    }

    static String saveBitmap( Bitmap bitmap, String dir, String baseName ) {
        try {
            File sdcard = Environment.getExternalStorageDirectory();
            File pictureDir = new File(sdcard, dir);
            pictureDir.mkdirs();
            File f = null;
            for (int i = 1; i < 200; ++i) {
                String name = baseName + i + ".jpg";
                f = new File(pictureDir, name);
                if (!f.exists()) {
                    break;
                }
            }
            if (!f.exists()) {
                String name = f.getAbsolutePath();
                FileOutputStream fos = new FileOutputStream(name);
                bitmap.compress( Bitmap.CompressFormat.JPEG, 100, fos );
                fos.flush();
                fos.close();
                return name;
            }
        } catch (Exception e) {
        } finally {
            /*
            if (fos != null) {
                fos.close();
            }
            */
        }
        return null;
    }
    
}
